package com.aspirecn.core.commons;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.validator.routines.UrlValidator;
import org.apache.log4j.Logger;

import com.aspirecn.core.ShareCommon;
import com.aspirecn.core.datacache.XssCache;
import com.aspirecn.core.object.XSSExclude;
import com.aspirecn.core.object.XSSJumper;
import com.aspirecn.core.object.XSSProject;

public class SecurityUtils {

	public final static Logger logger = Logger.getLogger(SecurityUtils.class);

	/**
	 * 校验请求参数名的合法性
	 * 
	 * @param args
	 */
	private static boolean validateParameterName(String key, String host) {

		if( StringUtils.isAlphanumeric(key) )//仅有0-9 a-z A-Z 的字符串也不校验
		{
			return true;
		}
		
		XSSProject xssProject = getXSSProject(host);

		for (String parameterName:xssProject.getParametername_filter()) {
			
			if (StringUtils.containsIgnoreCase(key, parameterName)
					&& StringUtils.isNotEmpty(StringUtils
							.trimToEmpty(parameterName))) {
				return false;
			}
		}

		return true;
	}

	/**
	 * 校验请求参数值的合法性
	 * 
	 * @param args
	 */
	private static boolean validateParameterValue(String value, String host) {

		if( NumberUtils.isNumber(value) )//数字型不校验
		{
			return true;
		}
		
		if( StringUtils.isAlphanumeric(value) )//仅有0-9 a-z A-Z 的字符串也不校验
		{
			return true;
		}
		
		//url并且host中包括i139.cn或10086.cn的不校验
		if( UrlValidator.getInstance().isValid(value) )
		{
			try {
				URL url = new URL(value);
				String serverName = url.getHost();
				
				String[] noCheckHost = Configuration.getInstance().getXssNoCheckHost();				
				if( ArrayUtils.isNotEmpty(noCheckHost) )
				{
					for( String h:noCheckHost )
					{
						if( StringUtils.contains(serverName, h) )
						{
							return true;
						}
					}
				}
				
			} catch (MalformedURLException e) {

				logger.error("链接参数校验逻辑失败", e);
			}
		}
		
		XSSProject xssProject = getXSSProject(host);

		for (String parameterValue : xssProject.getParametervalue_filter()) {
			if (StringUtils.containsIgnoreCase(value, parameterValue)
					&& StringUtils.isNotEmpty(StringUtils
							.trimToEmpty(parameterValue))) {
				return false;
			}
		}

		return true;
	}

	/**
	 * 校验，不正确直接跳入错误页了
	 * 返回跳转地址或空
	 * 
	 * @param httpServletRequest
	 * @param httpServletResponse
	 * @throws IOException
	 */
	public static String xssValidate(HttpServletRequest httpServletRequest,
			HttpServletResponse httpServletResponse) throws IOException {
		//参数名称列表
		Enumeration<String> enumeration = httpServletRequest
				.getParameterNames();
		//请求host
		String host = httpServletRequest.getServerName();//域名
		
		//校验配置
		XSSProject xssProject = getXSSProject(host);
		
		//此处添加循环，校验链接里面的参数是否需要校验，不需要continue;
		String currentUrl = LinkUtils.getCorrentURL(httpServletRequest);
		
		//校验时间，起始和终止时间一致不校验，格式HHmmss
		int starttime = NumberUtils.toInt(StringUtils.remove(xssProject.getStarttime(), ":"));
		int endtime   = NumberUtils.toInt(StringUtils.remove(xssProject.getEndtime(), ":"));
		int nowtime   = NumberUtils.toInt(DateFormatUtils.format(System.currentTimeMillis(), "HHmmss"));
		if( endtime > starttime )//截至时间》开始时间
		{
			//时间没到，不校验
			if( nowtime < starttime || nowtime > endtime  )
			{
				return null;
			}
		}
		
		String[] noCheckName = calNoCheckNames( xssProject.getExcludes(), currentUrl);

		//校验参数
		if (enumeration != null) {
			while (enumeration.hasMoreElements()) {//迭代校验参数
				
				String name = enumeration.nextElement();//参数名
						
				if( !ArrayUtils.contains(noCheckName, name) )
				{
					// 参数名校验错误
					if (!validateParameterName(name, host)) {
						
						String url = LinkUtils.addParameter(
								xssProject.getErrorurl(), "errorname",
								URLEncoder.encode(name, "utf-8"));
						logger.error("xss error： host=" + host + ",errorname=" + name + ",url=" + url);
						return url;
					}

					// 参数校验错误
					String value = httpServletRequest.getParameter(name);//参数值
					if (!validateParameterValue(value, host)) {
						String url = LinkUtils.addParameter(
								xssProject.getErrorurl(), "errorvalue",
								URLEncoder.encode(value, "utf-8"));	
						logger.error("xss error： host=" + host + ",errorvalue=" + value + ",url=" + url);
						return url;
					}
				}
			}
		}
		
		//jumper校验
		if( !ObjectUtils.isEmptyList(xssProject.getJumpers()) )
		{
			String jumpurl = calJumper( xssProject.getJumpers(), currentUrl );
			if( UrlValidator.getInstance().isValid(jumpurl) )//此方法已判断null
			{
				return jumpurl;
			}
		}
		
		
		return null;
	}

	private static XSSProject getXSSProject(String host) {
		XssCache xssCache = ShareCommon.getInstance().getXssCache();
		XSSProject xssProject = xssCache.getXSSProject(host);

		return xssProject;
	}
	
	
	
	public static String calJumper( List<XSSJumper> jumpList, String currentUrl )
	{
		if( ObjectUtils.isEmptyList(jumpList) )
		{
			return StringUtils.EMPTY;
		}
		
		for( XSSJumper jumper:jumpList )
		{
			String[] keywords = jumper.getKeywords();
			
			if( ArrayUtils.isNotEmpty(keywords) )
			{			
				boolean isJumper = true;
				
				for( String keyword:keywords )
				{
					if( StringUtils.startsWith(keyword, "!") )
					{
						String tempStr = StringUtils.substringAfter(keyword, "!");
						if( StringUtils.contains(currentUrl, tempStr) )
						{
							isJumper = false;
						}
					}
					else
					{
						String tempStr = keyword;
						if( !StringUtils.contains(currentUrl, tempStr) )
						{
							isJumper = false;
						}
					}
				}
				
				if( isJumper )
				{
					return jumper.getJumpurl();
				}
			}
		}		
		
		return StringUtils.EMPTY;
	}
	
	
	//计算不需要校验的参数名
	private static String[] calNoCheckNames( List<XSSExclude> exList, String currentUrl )
	{
		String[] noCheckName = null;//保存不需要校验的参数
		
		if( exList != null && !exList.isEmpty() )
		{
			for( XSSExclude exclude : exList )
			{
				if( exclude.isEmpty() )
				{
					continue;
				}
				
				//判断keyword是不是都在url里面
				boolean include = true;
				for( String s:exclude.getKeywords() )
				{
					//不包含，就校验，一个不包含就校验
					if( !StringUtils.containsIgnoreCase(currentUrl, s) )
					{
						include = false;
						break;
					}
				}
				
				//符合条件，加入不校验参数名
				if( include )
				{
					noCheckName = ArrayUtils.addAll(noCheckName, exclude.getNofilter_parametername());
				}
			}
		}
		
		return noCheckName;
	}
	

	public static void main(String[] args) throws MalformedURLException {
		String urlStr = "http://www.sina.com/aaaa/bbbb/ffff?dasdasd=312313&dad=4324";
		URL url = new URL(urlStr);

		System.out.println(url.getHost());
		System.out.println(UrlValidator.getInstance().isValid(urlStr));
		
		System.out.println(NumberUtils.isNumber("-11111"));
		
		System.out.println(StringUtils.isAlphanumeric("-11111"));
	}
}